/**
  ******************************************************************************
  * @file           : TokenManager.cpp
  * @author         : livio[yuanfeng1897@outlook.com]
  * @brief          : None
  * @attention      : None
  * @date           : 2023/3/2
  ******************************************************************************
  */

#include "TokenManager.h"
#include "Base64.h"

#include <array>
#include <charconv>
#include <chrono>
//#include <format>

#include <cstring>

// 签名
static auto
sign(const std::string &src,
     std::chrono::days dur) -> std::string {

    std::string timeBase64{"RkZGRkZGRkZGRkZGRkZGRg=="};
    if ((dur <=> std::chrono::days{0}) > 0) [[likely]] {
        auto endPoint = std::chrono::steady_clock::now() + dur;
        char endTime[16] = {'\0'};
        std::to_chars(endTime, endTime + 16,
                      endPoint.time_since_epoch().count(), 16);
        timeBase64 = Base64Encode((const unsigned char *) endTime, strlen(endTime));
    }
    // 进行加密（加密对称/非对称加密均可）
    return {timeBase64+src};
}

// 认证
static auto
verify(const std::string &token) -> bool {
    // 解密
    // 解析时间等数据
    // 解析时间是否过期

    return false;
}

TokenManager &TokenManager::instance() {
    static TokenManager ins;
    return ins;
}

auto TokenManager::generateToken(
        const std::string &id,
        std::chrono::days dur) -> std::string {
    auto idBase64 = Base64Encode((const unsigned char *) id.c_str(), id.length());
    auto strSign = sign(idBase64, dur);
    std::lock_guard<std::mutex> locker{tokenSetMtx};
    auto &&result = tokenSet.emplace(std::move(strSign));
    return {result.first->c_str(), result.first->length()};
}

auto TokenManager::destroyToken(const std::string &token) -> void {
    std::lock_guard<std::mutex> locker{tokenSetMtx};
    if (tokenSet.contains(token)) {
        tokenSet.erase(token);
    }
}

auto TokenManager::exist(const std::string &token) -> bool {
    std::lock_guard<std::mutex> locker{tokenSetMtx};
    return tokenSet.contains(token); //C++20
}

auto TokenManager::valid(const std::string &token) -> bool {
    std::lock_guard<std::mutex> locker{tokenSetMtx};
    if (!tokenSet.contains(token)) {
        return false;
    }
    return verify(token);
}

